/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package br.com.nsi.comm;

import gnu.io.*;
import java.awt.Color;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.TooManyListenersException;
import org.openide.util.Exceptions;

public class Communicator implements SerialPortEventListener
{
    //passed from main GUI
    //for containing the ports that will be found
    private Enumeration ports = null;
    //map the port names to CommPortIdentifiers
    private HashMap portMap = new HashMap();

    //this is the object that contains the opened port
    private CommPortIdentifier selectedPortIdentifier = null;
    private SerialPort serialPort = null;

    //input and output streams for sending and receiving data
    private InputStream input = null;
    private OutputStream output = null;

    //just a boolean flag that i use for enabling
    //and disabling buttons depending on whether the program
    //is connected to a serial port or not
    private boolean bConnected = false;

    //the timeout value for connecting with the port
    final static int TIMEOUT = 2000;

    //some ascii values for for certain things
    final static int SPACE_ASCII = 32;
    final static int DASH_ASCII = 45;
    final static int NEW_LINE_ASCII = 10;

    //a string for recording what goes on in the program
    //this string is written to the GUI
    String logText = "";

    public Communicator()
    {
       
    }

    //search for all the serial ports
    //pre: none
    //post: adds all the found ports to a combo box on the GUI
    public void searchForPorts()
    {
        ports = CommPortIdentifier.getPortIdentifiers();

        while (ports.hasMoreElements())
        {
            CommPortIdentifier curPort = (CommPortIdentifier)ports.nextElement();

            //get only serial ports
            if (curPort.getPortType() == CommPortIdentifier.PORT_SERIAL)
            {
               
                portMap.put(curPort.getName(), curPort);
            }
        }
    }

    //connect to the selected port in the combo box
    //pre: ports are already found by using the searchForPorts method
    //post: the connected comm port is stored in commPort, otherwise,
    //an exception is generated
    public void connect()
    {
        String selectedPort = "COM6";
        selectedPortIdentifier = (CommPortIdentifier)portMap.get(selectedPort);

        CommPort commPort = null;

        try
        {
            //the method below returns an object of type CommPort
            commPort = selectedPortIdentifier.open("br.com.nsi.comm", TIMEOUT);
            //the CommPort object can be casted to a SerialPort object
            serialPort = (SerialPort)commPort;
            serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
            //for controlling GUI elements
            setConnected(true);

            //logging
            logText = selectedPort + " opened successfully.";
            
            System.out.println(logText + "\n");

            //CODE ON SETTING BAUD RATE ETC OMITTED
            //XBEE PAIR ASSUMED TO HAVE SAME SETTINGS ALREADY

            //enables the controls on the GUI if a successful connection is made
            
        }
        catch (PortInUseException e)
        {
            logText = selectedPort + " is in use. (" + e.toString() + ")";
            
          
            System.out.println(logText + "\n");
        }
        catch (Exception e)
        {
            logText = "Failed to open " + selectedPort + "(" + e.toString() + ")";
            System.out.println(logText + "\n");
          
        }
    }

    //open the input and output streams
    //pre: an open port
    //post: initialized intput and output streams for use to communicate data
    public boolean initIOStream()
    {
        //return value for whather opening the streams is successful or not
        boolean successful = false;

        try {
            //
            input = serialPort.getInputStream();
            output = serialPort.getOutputStream();
            writeData(0, 0);
            
            successful = true;
            return successful;
        }
        catch (IOException e) {
            logText = "I/O Streams failed to open. (" + e.toString() + ")";
          
            System.out.println(logText + "\n");
            return successful;
        }
    }

    //starts the event listener that knows whenever data is available to be read
    //pre: an open serial port
    //post: an event listener for the serial port that knows when data is recieved
    public void initListener()
    {
        try
        {
            serialPort.addEventListener(this);
            serialPort.notifyOnDataAvailable(true);
        }
        catch (TooManyListenersException e)
        {
            logText = "Too many listeners. (" + e.toString() + ")";
            
            System.out.println(logText + "\n");
        }
    }

    //disconnect the serial port
    //pre: an open serial port
    //post: clsoed serial port
    public void disconnect()
    {
        //close the serial port
        try
        {
            writeData(0, 0);

            serialPort.removeEventListener();
            serialPort.close();
            input.close();
            output.close();
            setConnected(false);
            

            logText = "Disconnected.";
            
            System.out.println(logText + "\n");
        }
        catch (Exception e)
        {
            logText = "Failed to close " + serialPort.getName() + "(" + e.toString() + ")";
           
            System.out.println(logText + "\n");
        }
    }

    final public boolean getConnected()
    {
        return bConnected;
    }

    public void setConnected(boolean bConnected)
    {
        this.bConnected = bConnected;
    }

    //what happens when data is received
    //pre: serial event is triggered
    //post: processing on the data it reads
    public void serialEvent(SerialPortEvent evt) {
        
        System.out.println("#### EVENTO RECEBIDO ####");
        
        if (evt.getEventType() == SerialPortEvent.DATA_AVAILABLE)
        {
            try
            {
                if (input == null) {
                    return;
                }
                byte singleData = (byte)input.read();

                if (singleData != NEW_LINE_ASCII)
                {
                    logText = new String(new byte[] {singleData});
                    System.out.println("="+logText);
                }
                else
                {
                    System.out.println("\n");
                }
            }
            catch (Exception e)
            {
                logText = "Failed to read data. (" + e.toString() + ")";
              
                System.out.println(logText + "\n");
            }
        }
    }

    public void writeData(String msg){
        try {
            output.write(msg.getBytes());
            output.flush();
        } catch (IOException ex) {
            Exceptions.printStackTrace(ex);
        }
    }

    //method that can be called to send data
    //pre: open serial port
    //post: data sent to the other device
    public void writeData(int leftThrottle, int rightThrottle)
    {
        try
        {
            output.write(leftThrottle);
            output.flush();
            //this is a delimiter for the data
            output.write(DASH_ASCII);
            output.flush();
            
            output.write(rightThrottle);
            output.flush();
            //will be read as a byte so it is a space key
            output.write(SPACE_ASCII);
            output.flush();
        }
        catch (Exception e)
        {
            logText = "Failed to write data. (" + e.toString() + ")";
          
            System.out.println(logText + "\n");
        }
    }











    public void connect2() throws Exception {
		
		//impressao i = new impressao();
		//i.imprimi(new String[]{""}, 1, 1, "");
	

		try {
			//captura a lista de portas disponíveis,
			//pelo método estético em CommPortIdentifier.
			Enumeration pList = CommPortIdentifier.getPortIdentifiers();
			//CommPortIdentifier.getPortIdentifier("COM5");
			//Um mapping de nomes para CommPortIdentifiers.
			HashMap map = new HashMap();
	
			CommPortIdentifier cp = null; 
			
			//Procura pela porta desejada
			while (pList.hasMoreElements()) {
		        CommPortIdentifier cpi = (CommPortIdentifier)pList.nextElement();
		        map.put(cpi.getName(), cpi);
		        if (cpi.getPortType() == CommPortIdentifier.PORT_SERIAL) {
		        	cp = cpi;
		                System.err.println("PORTA SERIAL!!!!");
                                
		        }
		        if (cpi.getPortType() == CommPortIdentifier.PORT_PARALLEL) {
		        	System.err.println("PORTA PARALELA!!!!");
		        }
			}
			
			serialPort = (SerialPort)cp.open("COM1",3000);
			try {
				//setSerialPortParams(int baudrate, int dataBits, int stopBits, int parity)
				serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
			} catch (UnsupportedCommOperationException e) {
				e.printStackTrace();
			}
			
	      // input = serialPort.getInputStream();
		//	output = serialPort.getOutputStream();
		//	String msg = "teste de msg";
               //          System.out.println("encrevendo...");
			//output.write("<STX>".getBytes());
              //          output.flush();
		//	output.write("STX<->ACK".getBytes());
             //           output.flush();
                         System.out.println("OK");
	
		} catch (RuntimeException e) {
			e.printStackTrace();
		} finally {
			//serialPort.removeEventListener();
			//serialPort.close();
			
		}
                
                System.out.println("OK");
	}

}
